home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fsutil / fsutilRecovery.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-07  |  45.1 KB  |  1,664 lines

  1. /* 
  2.  * fsRecovery.c
  3.  *
  4.  *    Routines for filesytem recovery.  A file server keeps state about
  5.  *    client use, and this needs to be recovered after the server reboots.
  6.  *    The first routine, Fsutil_Reopen, goes through a sequence of steps that
  7.  *    a client makes in order to help the server in this way.  Other
  8.  *    routines are used by other parts of the filesystem to wait for
  9.  *    recovery to happen, and are typically invoked after a remote
  10.  *    operation fails due to a communication failure.  These are
  11.  *    Fsutil_WantRecovery, and Fsutil_WaitForRecovery.
  12.  *    The routine Fsutil_WaitForHost
  13.  *    is combines these two calls and is used by routines outside
  14.  *    the filesystem, i.e. when vm waits on swap files.
  15.  *
  16.  * Copyright 1987 Regents of the University of California.
  17.  * All rights reserved.
  18.  * Permission to use, copy, modify, and distribute this
  19.  * software and its documentation for any purpose and without
  20.  * fee is hereby granted, provided that the above copyright
  21.  * notice appear in all copies.  The University of California
  22.  * makes no representations about the suitability of this
  23.  * software for any purpose.  It is provided "as is" without
  24.  * express or implied warranty.
  25.  */
  26.  
  27. #ifndef lint
  28. static char rcsid[] = "$Header: /sprite/src/kernel/Cvsroot/kernel/fsutil/fsutilRecovery.c,v 9.24 93/01/06 17:28:54 mgbaker Exp $ SPRITE (Berkeley)";
  29. #endif not lint
  30.  
  31. #include <sprite.h>
  32. #include <fs.h>
  33. #include <fsutil.h>
  34. #include <fsprefix.h>
  35. #include <fsio.h>
  36. #include <fsrmt.h>
  37. #include <fsNameOps.h>
  38. #include <fsStat.h>
  39. #include <recov.h>
  40. #include <hash.h>
  41. #include <rpc.h>
  42. #include <vm.h>
  43. #include <rpcPacket.h>
  44.  
  45. #include <string.h>
  46. #include <stdio.h>
  47. #include <devClientDev.h>
  48.  
  49.  
  50. static void ReopenHandles _ARGS_((int serverID));
  51. static void RecoveryComplete _ARGS_((Fsutil_RecoveryInfo *recovPtr, 
  52.             ReturnStatus status));
  53. static void RecoveryNotify _ARGS_((Fsutil_RecoveryInfo *recovPtr));
  54. static Boolean RecoveryFailed _ARGS_((Fsutil_RecoveryInfo *recovPtr));
  55. static Boolean OkToScavenge _ARGS_((register Fsutil_RecoveryInfo *recovPtr));
  56. static void RecoveryDone _ARGS_((int serverID));
  57. extern Boolean RemoteHandle _ARGS_((Fs_HandleHeader *hdrPtr));
  58. extern ReturnStatus RecoveryWait _ARGS_((Fsutil_RecoveryInfo *recovPtr));
  59.  
  60. static ReturnStatus DoBulkReopen _ARGS_((int serverID));
  61. static void FinishReopenHandles _ARGS_((void));
  62. static ReturnStatus AddReopenHandle _ARGS_((Fs_HandleHeader *hdrPtr));
  63. static void InitReopenHandles _ARGS_((void));
  64.  
  65. /*
  66.  * The recovery state for each file is monitored.
  67.  */
  68. #define LOCKPTR (&recovPtr->lock)
  69.  
  70. /*
  71.  * Flags for the recovery state.
  72.  *    RECOVERY_NEEDED        The handle needs to be re-opened at the server.
  73.  *    RECOVERY_COMPLETE    The recovery actions have been completed.
  74.  *    RECOVERY_FAILED        The last re-open attempt failed.
  75.  */
  76. #define RECOVERY_NEEDED        0x1
  77. #define RECOVERY_COMPLETE    0x2
  78. #define RECOVERY_FAILED        0x4
  79.  
  80. /*
  81.  * A global counter of the clients active in recovery is kept.
  82.  * This is used to control print statements so we aren't noisey
  83.  * in the middle of recovery, but only at the beginning and end.
  84.  */
  85. int fsutil_NumRecovering = 0;
  86.  
  87.  
  88. /*
  89.  *----------------------------------------------------------------------
  90.  *
  91.  * Fsutil_Reopen --
  92.  *
  93.  *    Re-establish state with a file server.  First the prefixes for
  94.  *     the server are re-opened, then the handle table is scanned and
  95.  *    all handles from that server are re-opened.  We are called via
  96.  *    the recovery callbacks.  As a special favor to the VM module
  97.  *    we tell it after we have recovered state so that it can
  98.  *    recover after the swap server.
  99.  *
  100.  * Results:
  101.  *    None.
  102.  *
  103.  * Side effects:
  104.  *    None by this routine itself, but when this returns the routines
  105.  *    it has called will have reestablished state with the server.
  106.  *
  107.  *----------------------------------------------------------------------
  108.  */
  109. /*ARGSUSED*/
  110. void
  111. Fsutil_Reopen(serverID, clientData)
  112.     int serverID;        /* Server we are recovering with */
  113.     ClientData clientData;    /* IGNORED */
  114. {
  115.     Boolean        fastBoot;
  116.     Boolean        serverDriven;
  117.     unsigned int    state;
  118.  
  119.     /*
  120.      * Ensure only one instance of Fsutil_Reopen by doing a set-and-test.
  121.      */
  122.     if (Recov_SetClientState(serverID, SRV_RECOV_IN_PROGRESS)
  123.         & SRV_RECOV_IN_PROGRESS) {
  124.     return;
  125.     }
  126.     state = Recov_GetHostState(serverID);
  127.     fastBoot = state & RECOV_FAST_BOOT;
  128.     serverDriven = state & RECOV_SERVER_DRIVEN;
  129.     if (fastBoot && serverDriven) {
  130.     printf(
  131.     "Fsutil_Reopen: %d server doing both transparent and driven recovery\n",
  132.         serverID);
  133.     printf("\tI'll just do server-driven.\n");
  134.     fastBoot = FALSE;
  135.     }
  136.     if (state & SRV_DRIVEN_IN_PROGRESS) {
  137.     panic("Fsutil_Reopen: server-driven recovery out of order.");
  138.     }
  139.     if (serverDriven) {
  140.     /*
  141.      * We call back into the recovery module to wait for server rpc
  142.      * to wake us.  This will also wake up after some amount of time
  143.      * if we don't hear from server.
  144.      */
  145.     Recov_WaitForServerDriven(serverID);
  146.     }
  147.     /*
  148.      * Recover the prefix table.
  149.      */
  150.     Fsprefix_Reopen(serverID);
  151.  
  152.     if (!fastBoot || recov_ClientIgnoreTransparent) {
  153.     /*
  154.      * Wait for opens in progress, then block opens.
  155.      */
  156.     Fsprefix_RecoveryCheck(serverID);
  157.     /*
  158.      * Recover file handles
  159.      */
  160.     ReopenHandles(serverID);
  161.     /*
  162.      * Tell the server we're done.
  163.      */
  164.     RecoveryDone(serverID);
  165.     /*
  166.      * Allow regular opens.
  167.      */
  168.     Fsprefix_AllowOpens(serverID);
  169.     }
  170.     /*
  171.      * Clear the recovery bit before kicking processes.  Some processes
  172.      * may be locked down doing pseudo-device request/response, and the
  173.      * proc wakeup call will block on them.  To prevent deadlock we
  174.      * have to mark recovery as complete first.
  175.      */
  176.     Recov_ClearClientState(serverID, SRV_RECOV_IN_PROGRESS);
  177.     /*
  178.      * Tell VM that we have recovered in case this was the swap server.  
  179.      * This comes before we kick blocked processes, so that we can avoid a
  180.      * potential deadlock: if a process in the middle of forking hangs
  181.      * because the swap server is down, its child might be locked.  If this
  182.      * happens, the wakeup routine will hang waiting to unlock the child,
  183.      * which means the parent must be started first, so that the child will
  184.      * eventually be unlocked.  (See Sprite bug report 32338.)
  185.      */
  186.     Vm_Recovery();
  187.     /*
  188.      * Kick all processes in case any are blocking on I/O
  189.      */
  190.     Proc_WakeupAllProcesses();
  191. }
  192.  
  193. /*
  194.  *----------------------------------------------------------------------------
  195.  *
  196.  * ReopenHandles --
  197.  *
  198.  *    Called after the prefix table handles for the given server
  199.  *    have been recovered.  This scans the handle table twice
  200.  *    to recover I/O handles and streams.  The first pass re-opens
  201.  *    the I/O handles, and then streams are done.  A file-type specific
  202.  *    routine is called to do the reopen.  If the recovery fails this
  203.  *    logs a warning message and marks the handle as invalid.  A final
  204.  *    third pass over the handles is done to wakeup processes that are
  205.  *    waiting on recovery.
  206.  *
  207.  * Results:
  208.  *    None.
  209.  *
  210.  * Side effects:
  211.  *    This will invalidate handles for which recovery fails.  Invalid
  212.  *    I/O handles are removed from the handle table, while invalid
  213.  *    streams are left around because they get removed at close-time.
  214.  *
  215.  *----------------------------------------------------------------------------
  216.  */
  217.  
  218. static void
  219. ReopenHandles(serverID)
  220.     int        serverID;    /* The to re-establish contact with. */
  221. {
  222.     Hash_Search            hashSearch;
  223.     register    Fs_HandleHeader    *hdrPtr;
  224.     register    Fs_Stream    *streamPtr;
  225.     register    Fsrmt_IOHandle *rmtHandlePtr;
  226.     ReturnStatus        status = SUCCESS;
  227.     Boolean            printed = FALSE;
  228.     int                succeeded = fs_Stats.recovery.succeeded;
  229.     int                failed = fs_Stats.recovery.failed;
  230.                     /* This boolean is only to retry
  231.                      * stuff with single rpc's if the
  232.                      * server doesn't recognize a
  233.                      * bulk rpc.   GET RID OF IT WHEN
  234.                      * ALL KERNELS HAVE BULK RPC'S. */
  235.     Boolean            doBulkRpc = TRUE;
  236.     ReturnStatus        checkStatus = FAILURE;
  237.  
  238. doSingleRpcsInstead:
  239.     if (doBulkRpc && recov_BulkHandles && serverID == 53) {
  240.     InitReopenHandles();
  241.     }
  242.     if (!doBulkRpc) {
  243.     printf("Server %d couldn't do bulk reopen - starting again.\n",
  244.         serverID);
  245.     }
  246.     Hash_StartSearch(&hashSearch);
  247.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  248.      hdrPtr != (Fs_HandleHeader *) NIL;
  249.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  250.      if ((hdrPtr->fileID.type != FSIO_STREAM) &&
  251.          (hdrPtr->fileID.serverID == serverID)) {
  252.         if (!RemoteHandle(hdrPtr)) {
  253.         panic("ReopenHandles, local I/O handle at remote server?\n");
  254.         }
  255.         if (!printed) {
  256.         Net_HostPrint(serverID, "- recovering handles\n");
  257.         printed = TRUE;
  258.         }
  259. #ifdef NOTDEF
  260.  
  261. /*
  262.  * For debugging it would be nice to be able to check for this, but
  263.  * FS_HANDLE_INVALID isn't defined here.
  264.  */
  265.         if (hdrPtr->flags & FS_HANDLE_INVALID) {
  266.         printf("Attempting to reopen invalid handle!!!\n");
  267.         }
  268. #endif NOTDEF
  269.         if (doBulkRpc && recov_BulkHandles && serverID == 53) {
  270.         status = AddReopenHandle(hdrPtr);
  271.         if (status != SUCCESS && status != FS_NO_HANDLE) {
  272.             Fsutil_HandleUnlock(hdrPtr);
  273.         }
  274.         } else {
  275.         status = (*fsio_StreamOpTable[hdrPtr->fileID.type].reopen)
  276.             (hdrPtr, rpc_SpriteID, (ClientData)NIL, (int *)NIL,
  277.             (ClientData *)NIL);
  278.         if (status == FS_RECOV_SKIP) {
  279.             RecoveryComplete(&(((Fsrmt_IOHandle *)hdrPtr)->recovery),
  280.                     SUCCESS);
  281.         } else {
  282.             RecoveryComplete(&(((Fsrmt_IOHandle *)hdrPtr)->recovery),
  283.                     status);
  284.         }
  285.         /*
  286.          * If we removed the handle because it was no longer needed,
  287.          * we can't try unlocking it.
  288.          */
  289.         if (status != FS_NO_HANDLE) {
  290.             Fsutil_HandleUnlock(hdrPtr);
  291.         }
  292.         switch (status) {
  293.             case SUCCESS:
  294.             break;
  295.             case FS_NO_HANDLE:
  296.             /* We didn't need to recover this. */
  297.             break;
  298.             case RPC_SERVICE_DISABLED:
  299.             case RPC_TIMEOUT:
  300.             goto reopenReturn;
  301.             case FS_FILE_REMOVED:
  302.             case FS_RECOV_SKIP:
  303.             /*
  304.              * No noisy message, this is a common case.
  305.              */
  306.             break;
  307.             default:
  308.             Fsutil_FileError(hdrPtr, "Reopen failed ", status);
  309.             break;
  310.         }
  311.         }
  312.     } else {
  313.         Fsutil_HandleUnlock(hdrPtr);
  314.     }
  315.     }
  316.     if (doBulkRpc && recov_BulkHandles && serverID == 53) {
  317.     status = DoBulkReopen(serverID);
  318.     FinishReopenHandles();
  319.     if (status == RPC_INVALID_RPC) {
  320.         doBulkRpc = FALSE;
  321.         goto doSingleRpcsInstead;
  322.     }
  323.     if (status != SUCCESS) {
  324.         goto reopenReturn;
  325.     }
  326.     }
  327.     /*
  328.      * Now go through and recover streams, once we've gotten the regular
  329.      * I/O handles re-opened.  This ensures that the I/O handle will be
  330.      * around on the server when it re-creates our streams.  If recovery
  331.      * fails on a stream we invalidate its handle, but don't remove it
  332.      * because that happens in the top-level close routine.
  333.      */
  334.     if (doBulkRpc && recov_BulkHandles && serverID == 53) {
  335.     InitReopenHandles();
  336.     }
  337.     Hash_StartSearch(&hashSearch);
  338.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  339.      hdrPtr != (Fs_HandleHeader *) NIL;
  340.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  341.     checkStatus = FAILURE;
  342.     if ((hdrPtr->fileID.type == FSIO_STREAM) &&
  343.          (hdrPtr->fileID.serverID == serverID)) {
  344.         streamPtr = (Fs_Stream *)hdrPtr;
  345.         rmtHandlePtr = (Fsrmt_IOHandle *)streamPtr->ioHandlePtr;
  346.  
  347.         if (rmtHandlePtr == (Fsrmt_IOHandle *)NIL) {
  348.         Fsutil_FileError((Fs_HandleHeader *)streamPtr,
  349.             "ReopenHandles: NIL I/O handle", 0);
  350.         } else if (!RemoteHandle((Fs_HandleHeader *)rmtHandlePtr)) {
  351.         panic( "ReopenHandles: local I/O handle for remote stream?\n");
  352.         } else if (RecoveryFailed(&rmtHandlePtr->recovery)) {
  353.         Fsutil_HandleInvalidate((Fs_HandleHeader *)streamPtr);
  354.         } else {
  355.         if (doBulkRpc && recov_BulkHandles && serverID == 53) {
  356.             checkStatus =
  357.                 AddReopenHandle((Fs_HandleHeader *) streamPtr);
  358.         } else {
  359.             status = Fsio_StreamReopen((Fs_HandleHeader *)streamPtr,
  360.                     rpc_SpriteID, (ClientData)NIL, (int *)NIL,
  361.                     (ClientData *)NIL);
  362.             if (status != SUCCESS) {
  363.             Fsutil_FileError((Fs_HandleHeader *)streamPtr,
  364.                 "Reopen failed", status);
  365.             Fsutil_FileError(streamPtr->ioHandlePtr,"I/O handle",
  366.                     SUCCESS);
  367.             if ((status == RPC_TIMEOUT) ||
  368.                 (status == RPC_SERVICE_DISABLED)) {
  369.                 Fsutil_HandleUnlock(streamPtr);
  370.                 goto reopenReturn;
  371.             }
  372.             Fsutil_HandleInvalidate((Fs_HandleHeader *)streamPtr);
  373.             }
  374.         }
  375.         }
  376.     }
  377.     /*
  378.      * The only time we don't unlock the handle in this loop is if
  379.      * it was a stream handle we've put into the array for a bulk
  380.      * reopen.  That's only the case if the AddReopenHandle called
  381.      * returned with success.
  382.      */
  383.     if (!(doBulkRpc && recov_BulkHandles && serverID == 53 &&
  384.         checkStatus == SUCCESS)) {    
  385.         Fsutil_HandleUnlock(hdrPtr);
  386.     }
  387.     }
  388.  
  389.     if (doBulkRpc && recov_BulkHandles && serverID == 53) {
  390.     status = DoBulkReopen(serverID);
  391.     FinishReopenHandles();
  392.     if (status != SUCCESS) {
  393.         if (status != RPC_TIMEOUT && status != RPC_SERVICE_DISABLED) {
  394.         panic("Bad status from DoBulkReopen should be rpc-related.");
  395.         }
  396.         goto reopenReturn;
  397.     }
  398.     }
  399.     /*
  400.      * Now we notify processes waiting on I/O handles, and invalidate
  401.      * those I/O handles which failed recovery.
  402.      */
  403.     Hash_StartSearch(&hashSearch);
  404.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  405.      hdrPtr != (Fs_HandleHeader *) NIL;
  406.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  407.      if (!RemoteHandle(hdrPtr)) {
  408.          Fsutil_HandleUnlock(hdrPtr);
  409.      } else {
  410.          RecoveryNotify(&((Fsrmt_IOHandle *)hdrPtr)->recovery);
  411.          if (RecoveryFailed(&((Fsrmt_IOHandle *)hdrPtr)->recovery)) {
  412.          Fsutil_HandleInvalidate(hdrPtr);
  413.          }
  414.          Fsutil_HandleUnlock(hdrPtr);
  415.      }
  416.     }
  417. reopenReturn:
  418.     if (status != SUCCESS) {
  419.     Net_HostPrint(serverID, "Recovery failed: ");
  420.     Fsutil_PrintStatus(status);
  421.     printf("\n");
  422.     } else if (printed) {
  423.     Net_HostPrint(serverID, "Recovery complete");
  424.     printf(" %d handles reopened", fs_Stats.recovery.succeeded - succeeded);
  425.     if (fs_Stats.recovery.failed - failed > 0) {
  426.         printf(" %d failed reopens", fs_Stats.recovery.failed - failed);
  427.     }
  428.     printf("\n");
  429.     }
  430. }
  431.  
  432. /*
  433.  *----------------------------------------------------------------------
  434.  *
  435.  * Fsutil_RecoveryInit --
  436.  *
  437.  *    This routine is called to reset the recovery state for
  438.  *    a handle when it is first set up.
  439.  *
  440.  * Results:
  441.  *    None.
  442.  *
  443.  * Side effects:
  444.  *    Zero's out the struct.
  445.  *
  446.  *----------------------------------------------------------------------
  447.  */
  448. void
  449. Fsutil_RecoveryInit(recovPtr)
  450.     register Fsutil_RecoveryInfo    *recovPtr;    /* Recovery state */
  451. {
  452.     bzero((Address) recovPtr, sizeof(Fsutil_RecoveryInfo));
  453.     Sync_LockInitDynamic(&recovPtr->lock, "fs:recoveryLock");
  454. }
  455.  
  456. /*
  457.  *----------------------------------------------------------------------
  458.  *
  459.  * Fsutil_RecoverySyncLockCleanup --
  460.  *
  461.  *    This routine is called when removing a handle to .
  462.  *
  463.  * Results:
  464.  *    None.
  465.  *
  466.  * Side effects:
  467.  *    Zero's out the struct.
  468.  *
  469.  *----------------------------------------------------------------------
  470.  */
  471. /*ARGSUSED*/
  472. void
  473. Fsutil_RecoverySyncLockCleanup(recovPtr)
  474.     Fsutil_RecoveryInfo    *recovPtr;    /* Recovery state */
  475. {
  476.     Sync_LockClear(&recovPtr->lock);
  477. }
  478.  
  479. /*
  480.  *----------------------------------------------------------------------
  481.  *
  482.  * RemoteHandle --
  483.  *
  484.  *    This checks the type of a handle to see if it is remote and thus
  485.  *    has a Fsrmt_IOHandle structure embedded into it.  Only these
  486.  *    kinds of handles are manipulated by the recovery routines.
  487.  *
  488.  * Results:
  489.  *    TRUE if the handle has a remote server.
  490.  *
  491.  * Side effects:
  492.  *    None.
  493.  *
  494.  *----------------------------------------------------------------------
  495.  */
  496. Boolean
  497. RemoteHandle(hdrPtr)
  498.     Fs_HandleHeader *hdrPtr;
  499. {
  500.     switch(hdrPtr->fileID.type) {
  501.     case FSIO_RMT_FILE_STREAM:
  502.     case FSIO_RMT_DEVICE_STREAM:
  503.     case FSIO_RMT_PIPE_STREAM:
  504.     case FSIO_RMT_PSEUDO_STREAM:
  505.     case FSIO_PFS_NAMING_STREAM:
  506.     case FSIO_RMT_PFS_STREAM:
  507.     case FSIO_CONTROL_STREAM:
  508.     case FSIO_PFS_CONTROL_STREAM:
  509.         return(TRUE);
  510.     default:
  511.         return(FALSE);
  512.     }
  513. }
  514.  
  515. /*
  516.  *----------------------------------------------------------------------
  517.  *
  518.  * Fsutil_WaitForHost --
  519.  *
  520.  *    Wait until recovery actions have completed for the stream.
  521.  *    This will return failure codes if the recovery aborts.
  522.  *    If the non-blocking flag is passed in this just marks the
  523.  *    handle as needing recovery and returns SUCCESS.
  524.  *
  525.  * Results:
  526.  *    SUCCESS unless there was a recovery error.
  527.  *
  528.  * Side effects:
  529.  *    Block the process.
  530.  *
  531.  *----------------------------------------------------------------------
  532.  */
  533. ReturnStatus
  534. Fsutil_WaitForHost(streamPtr, flags, rpcStatus)
  535.     Fs_Stream    *streamPtr;
  536.     int        flags;        /* 0 or FS_NON_BLOCKING */
  537.     ReturnStatus rpcStatus;    /* Status that caused us to need recovery. */
  538. {
  539.     register Fs_HandleHeader *hdrPtr = streamPtr->ioHandlePtr;
  540.     register ReturnStatus status;
  541.  
  542.     Fsutil_WantRecovery(hdrPtr);
  543.     if (flags & FS_NON_BLOCKING) {
  544.     status = SUCCESS;
  545.     } else {
  546.     status = Fsutil_WaitForRecovery(hdrPtr, rpcStatus);
  547.     }
  548.     return(status);
  549. }
  550.  
  551. /*
  552.  *----------------------------------------------------------------------
  553.  *
  554.  * Fsutil_WantRecovery --
  555.  *
  556.  *    This routine is called when an error has occurred trying to
  557.  *    contact the file's IO server indicating that recovery actions
  558.  *    should take place when the server comes back.  We depend on
  559.  *    recovery call-backs already being installed as we don't even
  560.  *    mention our need to the recovery module here.
  561.  *
  562.  * Results:
  563.  *    None.
  564.  *
  565.  * Side effects:
  566.  *    Marks the handle as needing recovery.
  567.  *
  568.  *----------------------------------------------------------------------
  569.  */
  570. ENTRY void
  571. Fsutil_WantRecovery(hdrPtr)
  572.     Fs_HandleHeader *hdrPtr;    /* Handle needing recovery. The handle should
  573.                  * start with a FsRemoteHandle struct. */
  574. {
  575.     register Fsutil_RecoveryInfo *recovPtr = &((Fsrmt_IOHandle *)hdrPtr)->recovery;
  576.     if (!RemoteHandle(hdrPtr)) {
  577.     printf( "Fsutil_WantRecovery: no recovery for %s handles\n",
  578.         Fsutil_FileTypeToString(hdrPtr->fileID.type));
  579.     } else {
  580.     /*
  581.      * The monitor lock is embedded in RemoteIOHandles so we can
  582.      * only lock/unlock with the right kind of handle.
  583.      */
  584.     LOCK_MONITOR;
  585.     fs_Stats.recovery.wants++;
  586.     recovPtr->flags |= RECOVERY_NEEDED;
  587.     UNLOCK_MONITOR;
  588.     }
  589. }
  590.  
  591. /*
  592.  *----------------------------------------------------------------------
  593.  *
  594.  * Fsutil_AttemptRecovery --
  595.  *
  596.  *    Attempt recovery if the server appears up.  This is called
  597.  *    (in the background) by the block cleaner if it gets a stale
  598.  *    handle error on a write-back.
  599.  *
  600.  * Results:
  601.  *    None.
  602.  *
  603.  * Side effects:
  604.  *    Invokes the reopen procedure if the server responds to an RPC.
  605.  *
  606.  *----------------------------------------------------------------------
  607.  */
  608. void
  609. Fsutil_AttemptRecovery(data, callInfoPtr)
  610.     ClientData        data;        /* Ref to Fs_HandleHeader */
  611.     Proc_CallInfo    *callInfoPtr;
  612. {
  613.     register Fs_HandleHeader *hdrPtr =
  614.         (Fs_HandleHeader *)data;
  615.  
  616.     if (!RemoteHandle(hdrPtr)) {
  617.     /*
  618.      * We get called on a local naming request-response stream after the
  619.      * pseudo-filesystem server crashes.  There is no recovery possible
  620.      * so we just return an error and the naming operation fails.
  621.      */
  622.     printf( "Fsutil_AttemptRecovery, no recovery for type: %s\n",
  623.         Fsutil_FileTypeToString(hdrPtr->fileID.type));
  624.     return;
  625.     }
  626.     if (!Recov_IsHostDown(hdrPtr->fileID.serverID)) {
  627.     Fsutil_Reopen(hdrPtr->fileID.serverID, (ClientData)NIL);
  628.     }
  629.     callInfoPtr->interval = 0;    /* no more callbacks, please */
  630.     return;
  631. }
  632.  
  633. /*
  634.  *----------------------------------------------------------------------
  635.  *
  636.  * Fsutil_WaitForRecovery --
  637.  *
  638.  *    Wait until recovery actions have completed for the stream.
  639.  *    This will return failure codes if the recovery aborts.
  640.  *    The wait is interruptable by a signal so the user can abort.
  641.  *
  642.  * Results:
  643.  *    SUCCESS unless there was a recovery error or a signal came in.
  644.  *
  645.  * Side effects:
  646.  *    Block the process.
  647.  *
  648.  *----------------------------------------------------------------------
  649.  */
  650. ReturnStatus
  651. Fsutil_WaitForRecovery(hdrPtr, rpcStatus)
  652.     register Fs_HandleHeader    *hdrPtr;
  653.     ReturnStatus        rpcStatus;    /* Status that caused us to
  654.                          * need recovery. */
  655. {
  656.     ReturnStatus        status = SUCCESS;
  657.  
  658.     if (!RemoteHandle(hdrPtr)) {
  659.     /*
  660.      * We get called on a local naming request-response stream after the
  661.      * pseudo-filesystem server crashes.  There is no recovery possible
  662.      * so we just return an error and the naming operation fails.
  663.      */
  664.     printf( "Fsutil_WaitForRecovery, no recovery for type: %s\n",
  665.         Fsutil_FileTypeToString(hdrPtr->fileID.type));
  666.     return(FAILURE);
  667.     } else if (!Fsutil_HandleValid(hdrPtr)) {
  668.     /*
  669.      * Handle has already failed recovery.
  670.      */
  671.     return(FAILURE);
  672.     }
  673.     /*
  674.      * If our caller got a stale handle then the server is probably up
  675.      * we try to re-establish state with the server now.  Otherwise
  676.      * we depend on a reboot callback to invoke Fsutil_Reopen.
  677.      */
  678.     if (rpcStatus == FS_STALE_HANDLE) {
  679.     Fsutil_FileError(hdrPtr, "", rpcStatus);
  680.     if (!Recov_IsHostDown(hdrPtr->fileID.serverID)) {
  681.         Fsutil_Reopen(hdrPtr->fileID.serverID, (ClientData)NIL);
  682.     }
  683.     }
  684.     status = RecoveryWait(&((Fsrmt_IOHandle *)hdrPtr)->recovery);
  685.     return(status);
  686. }
  687.  
  688. /*
  689.  *----------------------------------------------------------------------
  690.  *
  691.  * RecoveryWait --
  692.  *
  693.  *    Wait until recovery actions have completed for the stream.
  694.  *    This will return failure codes if the recovery aborts.
  695.  *
  696.  * Results:
  697.  *    SUCCESS unless there was a recovery error.
  698.  *
  699.  * Side effects:
  700.  *    Block the process.
  701.  *
  702.  *----------------------------------------------------------------------
  703.  */
  704. ENTRY ReturnStatus
  705. RecoveryWait(recovPtr)
  706.     Fsutil_RecoveryInfo *recovPtr;
  707. {
  708.     register ReturnStatus status = SUCCESS;
  709.     LOCK_MONITOR;
  710.     while (recovPtr->flags & RECOVERY_NEEDED) {
  711.     if (Sync_Wait(&recovPtr->reopenComplete, TRUE)) {
  712.         status = GEN_ABORTED_BY_SIGNAL;
  713.         fs_Stats.recovery.waitAbort++;
  714.         break;
  715.     }
  716.     }
  717.     if (recovPtr->flags & RECOVERY_FAILED) {
  718.     status = recovPtr->status;
  719.     fs_Stats.recovery.waitFailed++;
  720.     } else if (status == SUCCESS) {
  721.     fs_Stats.recovery.waitOK++;
  722.     }
  723.     UNLOCK_MONITOR;
  724.     return(status);
  725. }
  726.  
  727. /*
  728.  *----------------------------------------------------------------------------
  729.  *
  730.  * RecoveryComplete --
  731.  *
  732.  *    Mark a remote handle as having competed recovery actions.  The waiting
  733.  *    process is not woken up yet, however, because it may also depend
  734.  *    on recovery of the shadow streams kept on the server.  FsHandleReopen
  735.  *    will call RecoveryNotify to poke waiters after all handles have been
  736.  *    recovered.  Note that this procedure won't mark the handle as
  737.  *    having completed recovery if the error status indicates a timeout.
  738.  *
  739.  * Results:
  740.  *    None.
  741.  *
  742.  * Side effects:
  743.  *    The handle is marked as having competed recovery if the error
  744.  *    status does not indicate another communcation fail with the server.
  745.  *
  746.  *----------------------------------------------------------------------------
  747.  *
  748.  */
  749. ENTRY static void
  750. RecoveryComplete(recovPtr, status)
  751.     Fsutil_RecoveryInfo *recovPtr;
  752.     ReturnStatus status;
  753. {
  754.     LOCK_MONITOR;
  755.  
  756.     recovPtr->status = status;
  757.     switch(status) {
  758.     case RPC_TIMEOUT:
  759.     case RPC_SERVICE_DISABLED:
  760.         fs_Stats.recovery.timeout++;
  761.         break;
  762.     case FS_FILE_REMOVED:
  763.         recovPtr->flags |= RECOVERY_FAILED|RECOVERY_COMPLETE;
  764.         fs_Stats.recovery.deleted++;
  765.         break;
  766.     default:
  767.         recovPtr->flags |= RECOVERY_FAILED|RECOVERY_COMPLETE;
  768.         fs_Stats.recovery.failed++;
  769.         break;
  770.      case SUCCESS:
  771.         recovPtr->flags |= RECOVERY_COMPLETE;
  772.         fs_Stats.recovery.succeeded++;
  773.         break;
  774.     }
  775.  
  776.     UNLOCK_MONITOR;
  777. }
  778.  
  779. /*
  780.  *----------------------------------------------------------------------------
  781.  *
  782.  * RecoveryNotify --
  783.  *
  784.  *    Wakeup processes waiting on recovery for a handle, if appropriate.
  785.  *    This is called from FsReopenHandle after all handles, both I/O
  786.  *    handles and top-level stream, have been recovered.
  787.  *
  788.  * Results:
  789.  *    None.
  790.  *
  791.  * Side effects:
  792.  *    Processes waiting on the handle are awakened and the RECOVERY_NEEDED
  793.  *    flags is cleared from the recovery flags.
  794.  *
  795.  *----------------------------------------------------------------------------
  796.  *
  797.  */
  798. ENTRY static void
  799. RecoveryNotify(recovPtr)
  800.     register Fsutil_RecoveryInfo *recovPtr;
  801. {
  802.     LOCK_MONITOR;
  803.  
  804.     if (recovPtr->flags & RECOVERY_COMPLETE) {
  805.     recovPtr->flags &= ~(RECOVERY_COMPLETE|RECOVERY_NEEDED);
  806.     Sync_Broadcast(&recovPtr->reopenComplete);
  807.     }
  808.  
  809.     UNLOCK_MONITOR;
  810. }
  811.  
  812. /*
  813.  *----------------------------------------------------------------------
  814.  *
  815.  * Fsutil_RecoveryNeeded --
  816.  *
  817.  *    Returns TRUE if recovery is pending for the handle.  This is
  818.  *    called when scavenging a remote file handle to make sure noone
  819.  *    is waiting for recovery on the handle.
  820.  *
  821.  * Results:
  822.  *    TRUE or FALSE.
  823.  *
  824.  * Side effects:
  825.  *    None.
  826.  *
  827.  *----------------------------------------------------------------------
  828.  */
  829. ENTRY Boolean
  830. Fsutil_RecoveryNeeded(recovPtr)
  831.     Fsutil_RecoveryInfo *recovPtr;
  832. {
  833.     register Boolean recovWanted;
  834.     LOCK_MONITOR;
  835.     recovWanted = (recovPtr->flags & RECOVERY_NEEDED);
  836.     UNLOCK_MONITOR;
  837.     return(recovWanted);
  838. }
  839.  
  840. /*
  841.  *----------------------------------------------------------------------
  842.  *
  843.  * RecoveryFailed --
  844.  *
  845.  *    Returns TRUE if recovery has failed on the handle.  This is
  846.  *    called when recovering streams to see if the I/O handle is ok.
  847.  *
  848.  * Results:
  849.  *    TRUE or FALSE.
  850.  *
  851.  * Side effects:
  852.  *    None.
  853.  *
  854.  *----------------------------------------------------------------------
  855.  */
  856. ENTRY static Boolean
  857. RecoveryFailed(recovPtr)
  858.     Fsutil_RecoveryInfo *recovPtr;
  859. {
  860.     register Boolean recovFailed;
  861.     LOCK_MONITOR;
  862.     recovFailed = (recovPtr->flags & RECOVERY_FAILED);
  863.     UNLOCK_MONITOR;
  864.     return(recovFailed);
  865. }
  866.  
  867. /*
  868.  *----------------------------------------------------------------------------
  869.  *
  870.  * FsRemoteHandleScavange --
  871.  *
  872.  *    Scavenging routine for remote handles, not including remote
  873.  *    file handles. This nukes the handle if there are no uses of
  874.  *    it and it doesn't need recovery.
  875.  *
  876.  * Results:
  877.  *    TRUE if the handle was removed.
  878.  *
  879.  * Side effects:
  880.  *    Either removes or unlocks the handle.
  881.  *
  882.  *----------------------------------------------------------------------------
  883.  *
  884.  */
  885. Boolean
  886. Fsutil_RemoteHandleScavenge(hdrPtr)
  887.     Fs_HandleHeader *hdrPtr;
  888. {
  889.     if (OkToScavenge(&((Fsrmt_IOHandle *)hdrPtr)->recovery)) {
  890.     Fsutil_RecoverySyncLockCleanup(&((Fsrmt_IOHandle *)hdrPtr)->recovery);
  891.     Fsutil_HandleRemove(hdrPtr);
  892.     return(TRUE);
  893.     } else {
  894.     Fsutil_HandleUnlock(hdrPtr);
  895.     return(FALSE);
  896.     }
  897. }
  898.  
  899. /*
  900.  *----------------------------------------------------------------------------
  901.  *
  902.  * OkToScavenge --
  903.  *
  904.  *    Internal routine to check monitored state.  This returns TRUE if
  905.  *    the handle should be scavenged, in which case our caller can
  906.  *    remove the handle, or FALSE, in which our caller should just
  907.  *    unlock it.
  908.  *
  909.  * Results:
  910.  *    None.
  911.  *
  912.  * Side effects:
  913.  *    None.
  914.  *
  915.  *----------------------------------------------------------------------------
  916.  *
  917.  */
  918. static ENTRY Boolean
  919. OkToScavenge(recovPtr)
  920.     register Fsutil_RecoveryInfo *recovPtr;
  921. {
  922.     register Boolean okToScavenge = FALSE;
  923.     LOCK_MONITOR;
  924.     if (recovPtr->use.ref == 0 &&
  925.     (recovPtr->flags & RECOVERY_NEEDED) == 0) {
  926.     okToScavenge = TRUE;
  927.     }
  928.     UNLOCK_MONITOR;
  929.     return(okToScavenge);
  930. }
  931.  
  932. /*
  933.  *----------------------------------------------------------------------
  934.  *
  935.  * Fsutil_ClientCrashed --
  936.  *
  937.  *    Clean up state after a host goes down.  Mainly we want to close
  938.  *    files opened on that client.  We also take care to reset various
  939.  *    watchdogs like the bit that turns off opens until re-opens are done.
  940.  *
  941.  * Results:
  942.  *    None.
  943.  *
  944.  * Side effects:
  945.  *    Cleans up references the client had to files.  Clears the
  946.  *    CLT_RECOV_IN_PROGRESS bit from the client recovery state.
  947.  *
  948.  *----------------------------------------------------------------------
  949.  */
  950. /*ARGSUSED*/
  951. void
  952. Fsutil_ClientCrashed(spriteID, clientData)
  953.     int spriteID;        /* Client that crashed */
  954.     ClientData clientData;    /* IGNORED */
  955. {
  956.     fs_Stats.recovery.clientCrashed++;
  957.     /*
  958.      * Reset the 'recovery in progress' bit (it would be set if the
  959.      * client crashed during recovery) so the client can open files
  960.      * the next time it boots.
  961.      */
  962.     Recov_ClearClientState(spriteID,
  963.         CLT_RECOV_IN_PROGRESS | CLT_OLD_RECOV | CLT_DOING_SRV_RECOV);
  964.     /*
  965.      * Clean up references to our files.
  966.      */
  967.     Fsutil_RemoveClient(spriteID);
  968. }
  969.  
  970. /*
  971.  *----------------------------------------------------------------------------
  972.  *
  973.  * Fsutil_RemoveClient --
  974.  *
  975.  *    Go through all of the handles and delete all references to the
  976.  *    handle for the client.  This is to be called when a client reboots.
  977.  *    The clientKill procedure for each I/O handle type must either
  978.  *    unlock the handle or remove it after cleaning up.
  979.  *
  980.  * Results:
  981.  *    None.
  982.  *
  983.  * Side effects:
  984.  *    Calls the stream-type-specific clientKill procedures.
  985.  *
  986.  *----------------------------------------------------------------------------
  987.  *
  988.  */
  989.  
  990. void
  991. Fsutil_RemoveClient(clientID)
  992.     int        clientID;    /* The client to remove the files for. */
  993. {
  994.     Hash_Search            hashSearch;
  995.     register    Fs_HandleHeader    *hdrPtr;
  996.  
  997.     Hash_StartSearch(&hashSearch);
  998.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  999.      hdrPtr != (Fs_HandleHeader *) NIL;
  1000.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  1001.     (*fsio_StreamOpTable[hdrPtr->fileID.type].clientKill)(hdrPtr, clientID);
  1002.     }
  1003. }
  1004.  
  1005.  
  1006. #ifdef not_used
  1007.  
  1008. /*
  1009.  *----------------------------------------------------------------------
  1010.  *
  1011.  * FsRecoveryStarting --
  1012.  *
  1013.  *    This tells the server that we are starting recovery so that it
  1014.  *    can prevent open requests by us.
  1015.  *
  1016.  * Results:
  1017.  *    None.
  1018.  *
  1019.  * Side effects:
  1020.  *    An RPC to the server.
  1021.  *
  1022.  *----------------------------------------------------------------------
  1023.  */
  1024. ENTRY void
  1025. FsRecoveryStarting(serverID)
  1026.     int serverID;        /* Server we are recovering with */
  1027. {
  1028.     Rpc_Storage storage;
  1029.     int flags = CLT_RECOV_IN_PROGRESS;
  1030.  
  1031.     storage.requestParamPtr = (Address)&flags;
  1032.     storage.requestParamSize = sizeof(int);
  1033.     storage.requestDataPtr = (Address)NIL;
  1034.     storage.requestDataSize = 0;
  1035.     storage.replyParamPtr = (Address)NIL;
  1036.     storage.replyParamSize = 0;
  1037.     storage.replyDataPtr = (Address)NIL;
  1038.     storage.replyDataSize = 0;
  1039.  
  1040.     status = Rpc_Call(serverID, RPC_FS_RECOVERY, &storage);
  1041.     if (status != SUCCESS) {
  1042.     printf( "FsRecoveryDone: got status %x\n", status);
  1043.     }
  1044. }
  1045. #endif not_used
  1046.  
  1047. /*
  1048.  *----------------------------------------------------------------------
  1049.  *
  1050.  * RecoveryDone --
  1051.  *
  1052.  *    This tells the server that we are done with recovery so that it
  1053.  *    will start handling open requests from us.
  1054.  *
  1055.  * Results:
  1056.  *    None.
  1057.  *
  1058.  * Side effects:
  1059.  *    An RPC to the server.
  1060.  *
  1061.  *----------------------------------------------------------------------
  1062.  */
  1063. ENTRY static void
  1064. RecoveryDone(serverID)
  1065.     int serverID;        /* Server we are recovering with */
  1066. {
  1067.     Rpc_Storage storage;
  1068.     ReturnStatus status;
  1069.     int flags = 0;
  1070.  
  1071.     storage.requestParamPtr = (Address)&flags;
  1072.     storage.requestParamSize = sizeof(int);
  1073.     storage.requestDataPtr = (Address)NIL;
  1074.     storage.requestDataSize = 0;
  1075.     storage.replyParamPtr = (Address)NIL;
  1076.     storage.replyParamSize = 0;
  1077.     storage.replyDataPtr = (Address)NIL;
  1078.     storage.replyDataSize = 0;
  1079.  
  1080.     status = Rpc_Call(serverID, RPC_FS_RECOVERY, &storage);
  1081.     if (status != SUCCESS) {
  1082.     printf( "RecoveryDone: got status %x\n", status);
  1083.     } else {
  1084.     fs_Stats.recovery.number++;
  1085.     }
  1086. }
  1087.  
  1088. /*
  1089.  *----------------------------------------------------------------------
  1090.  *
  1091.  * Fsutil_RpcRecovery --
  1092.  *
  1093.  *    Rpc server stub for RPC_FS_RECOVERY RPC.  The client us
  1094.  *    before and after it is re-opening its files.  This lets us
  1095.  *    block out regular open requests until the re-opening is done.
  1096.  *
  1097.  * Results:
  1098.  *    None.
  1099.  *
  1100.  * Side effects:
  1101.  *    Maintains the "client is recovering" state bit.
  1102.  *
  1103.  *----------------------------------------------------------------------
  1104.  */
  1105. /*ARGSUSED*/
  1106. ReturnStatus
  1107. Fsutil_RpcRecovery(srvToken, clientID, command, storagePtr)
  1108.     ClientData srvToken;    /* Handle on server process passed to
  1109.                  * Rpc_Reply */
  1110.     int clientID;        /* Sprite ID of client host */
  1111.     int command;        /* Command identifier */
  1112.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  1113.                  * buffers and also indicate the exact amount
  1114.                  * of data in the request buffers.  The reply
  1115.                  * fields are initialized to NIL for the
  1116.                  * pointers and 0 for the lengths.  This can
  1117.                  * be passed to Rpc_Reply */
  1118. {
  1119.     int *flagsPtr = (int *)storagePtr->requestParamPtr;
  1120.     if (*flagsPtr & CLT_RECOV_IN_PROGRESS) {
  1121.     if ((Recov_GetClientState(clientID) & CLT_RECOV_IN_PROGRESS) == 0) {
  1122.         fsutil_NumRecovering++;
  1123.         if (fsutil_NumRecovering == 1) {
  1124.         Net_HostPrint(clientID, "initiated client recovery\n");
  1125.         }
  1126.         Recov_SetClientState(clientID, CLT_RECOV_IN_PROGRESS);
  1127.     }
  1128.     fs_Stats.recovery.clientRecovered++;
  1129.     } else {
  1130.     Recov_ClearClientState(clientID, CLT_RECOV_IN_PROGRESS);
  1131.     fsutil_NumRecovering--;
  1132.     if (fsutil_NumRecovering == 0) {
  1133.         Net_HostPrint(clientID, "completed client recovery\n");
  1134.     }
  1135.     }
  1136.     Rpc_Reply(srvToken, SUCCESS, storagePtr, (int(*)())NIL, (ClientData)NIL);
  1137.     return(SUCCESS);
  1138. }
  1139.  
  1140.  
  1141. /*
  1142.  *----------------------------------------------------------------------
  1143.  *
  1144.  * Fsutil_FsRecovInfo --
  1145.  *
  1146.  *    Info, including file names, about recovery and file status for testing.
  1147.  *
  1148.  * Results:
  1149.  *    SUCCESS or not.
  1150.  *
  1151.  * Side effects:
  1152.  *    None.
  1153.  *
  1154.  *----------------------------------------------------------------------
  1155.  */
  1156. ReturnStatus
  1157. Fsutil_FsRecovInfo(length, resultPtr, lengthNeededPtr)
  1158.     int                length;        /* size of data buffer */
  1159.     Fsutil_FsRecovNamedStats    *resultPtr;    /* data buffer */
  1160.     int                *lengthNeededPtr;
  1161. {
  1162.     Hash_Search            hashSearch;
  1163.     Fs_HandleHeader        *hdrPtr;
  1164.     Fsutil_FsRecovNamedStats    *infoPtr;
  1165.     int                numNeeded;
  1166.     int                numAvail;
  1167.     Fs_HandleHeader        *testHandlePtr;
  1168.  
  1169.     if (resultPtr != (Fsutil_FsRecovNamedStats *) NIL) {
  1170.     bzero((char *) resultPtr, length);
  1171.     }
  1172.     numNeeded = 0;
  1173.     numAvail = length / sizeof (Fsutil_FsRecovNamedStats);
  1174.  
  1175.     infoPtr = (Fsutil_FsRecovNamedStats *) resultPtr;
  1176.  
  1177.     Hash_StartSearch(&hashSearch);
  1178.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  1179.      hdrPtr != (Fs_HandleHeader *) NIL;
  1180.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  1181.  
  1182.     numNeeded++;
  1183.     if (numNeeded > numAvail) {
  1184.         Fsutil_HandleUnlock(hdrPtr);
  1185.         continue;
  1186.     }
  1187.     if (hdrPtr->fileID.type == FSIO_STREAM) {
  1188.         Fs_Stream    *streamPtr;
  1189.  
  1190.         streamPtr = (Fs_Stream *) hdrPtr;
  1191.  
  1192.         infoPtr->streamRefCount = hdrPtr->refCount;
  1193.         infoPtr->mode = streamPtr->flags;
  1194.         infoPtr->streamHandle = TRUE;
  1195.  
  1196.         testHandlePtr = streamPtr->ioHandlePtr;
  1197.     } else {
  1198.         infoPtr->streamHandle = FALSE;
  1199.         testHandlePtr = hdrPtr;
  1200.     }
  1201.  
  1202.     if (testHandlePtr != (Fs_HandleHeader *) NIL) {
  1203.         infoPtr->fileID = testHandlePtr->fileID;
  1204.  
  1205.         if (fsio_StreamRecovTestFuncs[testHandlePtr->fileID.type].refFunc
  1206.             != (int ((*)())) NIL) {
  1207.         infoPtr->refCount =
  1208.             (*(fsio_StreamRecovTestFuncs[
  1209.             testHandlePtr->fileID.type]).refFunc) (testHandlePtr);
  1210.         }
  1211.         if (fsio_StreamRecovTestFuncs[
  1212.             testHandlePtr->fileID.type].numBlocksFunc !=
  1213.             (int ((*)())) NIL) {
  1214.         infoPtr->numBlocks =
  1215.             (*(fsio_StreamRecovTestFuncs[
  1216.             testHandlePtr->fileID.type]).numBlocksFunc)
  1217.             (testHandlePtr);
  1218.         }
  1219.         if (fsio_StreamRecovTestFuncs[
  1220.             testHandlePtr->fileID.type].numDirtyBlocksFunc
  1221.             != (int ((*)())) NIL) {
  1222.         infoPtr->numDirtyBlocks =
  1223.             (*(fsio_StreamRecovTestFuncs[
  1224.             testHandlePtr->fileID.type]).numDirtyBlocksFunc)
  1225.             (testHandlePtr);
  1226.         }
  1227.         (void)strncpy(infoPtr->name, Fsutil_HandleName(testHandlePtr), 49);
  1228.         infoPtr->name[50] = '\0';
  1229.     }
  1230.     infoPtr++;
  1231.     Fsutil_HandleUnlock(hdrPtr);
  1232.     }
  1233.     *lengthNeededPtr = numNeeded * sizeof (Fsutil_FsRecovNamedStats);
  1234.  
  1235.     return SUCCESS;
  1236. }
  1237.  
  1238. /*
  1239.  *----------------------------------------------------------------------------
  1240.  *
  1241.  * Fsutil_TestForHandles --
  1242.  *
  1243.  *    Called to see if we still have handles for the given serverID.
  1244.  *
  1245.  * Results:
  1246.  *    Number of file and device handles for server in question.
  1247.  *
  1248.  * Side effects:
  1249.  *    None.
  1250.  *
  1251.  *----------------------------------------------------------------------------
  1252.  */
  1253. int
  1254. Fsutil_TestForHandles(serverID)
  1255.     int        serverID;    /* Server we're interested in. */
  1256. {
  1257.     Hash_Search            hashSearch;
  1258.     register    Fs_HandleHeader    *hdrPtr;
  1259.     int                count = 0;
  1260.  
  1261.     Hash_StartSearch(&hashSearch);
  1262.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  1263.      hdrPtr != (Fs_HandleHeader *) NIL;
  1264.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  1265.      if (hdrPtr->fileID.serverID == serverID) {
  1266.         switch(hdrPtr->fileID.type) {
  1267. /*
  1268.         case FSIO_RMT_PSEUDO_STREAM:
  1269.         case FSIO_STREAM:
  1270. */
  1271.         case FSIO_RMT_FILE_STREAM:
  1272.         case FSIO_RMT_DEVICE_STREAM:
  1273.         count++;
  1274.         break;
  1275.         default:
  1276.         break;
  1277.         }
  1278.     }
  1279.     Fsutil_HandleUnlock(hdrPtr);
  1280.     }
  1281.     return count;
  1282. }
  1283.  
  1284. /* Number of handles to be put together. */
  1285. int            numBulkHandles = 0;
  1286. /* Current handle we're filling in. */
  1287. int            nextHandleIndex = 0;
  1288. /* Array of handle reopen information, etc. */
  1289. static Fsutil_BulkHandle    *bulkHandleSpace = (Fsutil_BulkHandle *) NIL;
  1290. /* Array of info returned from server for bulk reopen. */
  1291. static Fsutil_BulkReturn    *bulkReturnSpace = (Fsutil_BulkReturn *) NIL;
  1292. static Fsutil_BulkReopenOps    bulkReopenOps[FSIO_NUM_STREAM_TYPES];
  1293.  
  1294.  
  1295. /*
  1296.  *----------------------------------------------------------------------------
  1297.  *
  1298.  * InitReopenHandles --
  1299.  *
  1300.  *    Initialize memory for storing future reopen rpc info.
  1301.  *
  1302.  * Results:
  1303.  *    None.
  1304.  *
  1305.  * Side effects:
  1306.  *    Memory allocated.
  1307.  *
  1308.  *----------------------------------------------------------------------------
  1309.  */
  1310. static void
  1311. InitReopenHandles()
  1312. {
  1313.     int     i;
  1314.  
  1315.     if (numBulkHandles < fs_Stats.handle.maxNumber) {
  1316.     if (numBulkHandles > 0) {
  1317.         free((Address) bulkHandleSpace);
  1318.     }
  1319.     numBulkHandles = fs_Stats.handle.maxNumber;
  1320.     bulkHandleSpace = (Fsutil_BulkHandle *)
  1321.         malloc(numBulkHandles * sizeof (Fsutil_BulkHandle));
  1322.     bulkReturnSpace = (Fsutil_BulkReturn *)
  1323.         malloc(numBulkHandles * sizeof (Fsutil_BulkReturn));
  1324.     }
  1325.     /*
  1326.      * Initialize all to be "empty."
  1327.      */
  1328.     for (i = 0; i < numBulkHandles; i++) {
  1329.     bulkHandleSpace[i].type = -1;
  1330.     }
  1331.     nextHandleIndex = 0;
  1332.     return;
  1333. }
  1334.  
  1335. /*
  1336.  *----------------------------------------------------------------------------
  1337.  *
  1338.  * Dummy functions for bulk reopens - setup and finish --
  1339.  *
  1340.  *
  1341.  * Results:
  1342.  *    None.
  1343.  *
  1344.  * Side effects:
  1345.  *    None.
  1346.  *
  1347.  *----------------------------------------------------------------------------
  1348.  */
  1349. ReturnStatus
  1350. NoSetupFunc(hdrPtr, paramsPtr)
  1351.     Fs_HandleHeader    *hdrPtr;
  1352.     Address        paramsPtr;
  1353. {
  1354.     return FAILURE;
  1355. }
  1356. void
  1357. NoFinishFunc(hdrPtr, statePtr, status)
  1358.     Fs_HandleHeader    *hdrPtr;
  1359.     Address        statePtr;
  1360.     ReturnStatus    status;
  1361. {
  1362.     return;
  1363. }
  1364.  
  1365.  
  1366.  
  1367. /*
  1368.  *----------------------------------------------------------------------------
  1369.  *
  1370.  * Fsutil_InitBulkReopenTables --
  1371.  *
  1372.  *    Initialize the bulk reopen ops to be ops used for when there is
  1373.  *    no recovery for the handle type.
  1374.  *
  1375.  * Results:
  1376.  *    None.
  1377.  *
  1378.  * Side effects:
  1379.  *    None.
  1380.  *
  1381.  *----------------------------------------------------------------------------
  1382.  */
  1383. void
  1384. Fsutil_InitBulkReopenTables()
  1385. {
  1386.     int        i;
  1387.  
  1388.     for (i = 0; i < FSIO_NUM_STREAM_TYPES; i++) {
  1389.     /*
  1390.      * Check first to make sure it hasn't already been set with a valid
  1391.      * function.
  1392.      */
  1393.     if ((int) (bulkReopenOps[i].setup) == 0) {
  1394.         bulkReopenOps[i].setup = NoSetupFunc;
  1395.         bulkReopenOps[i].finish = NoFinishFunc;
  1396.     }
  1397.     }
  1398.     return;
  1399. }
  1400.  
  1401. int    reopensSkipped;
  1402.  
  1403. /*
  1404.  *----------------------------------------------------------------------------
  1405.  *
  1406.  * Fsutil_InitBulkReopenOps --
  1407.  *
  1408.  *    Copy a handle type's reopen ops to the array.
  1409.  *
  1410.  * Results:
  1411.  *    None.
  1412.  *
  1413.  * Side effects:
  1414.  *    None.
  1415.  *
  1416.  *----------------------------------------------------------------------------
  1417.  */
  1418. void
  1419. Fsutil_InitBulkReopenOps(type, reopenOpsPtr)
  1420.     int                type;
  1421.     Fsutil_BulkReopenOps    *reopenOpsPtr;
  1422. {
  1423.     if (type >= FSIO_NUM_STREAM_TYPES) {
  1424.     panic("Fsutil_InitBulkReopenOps: bad handle type.");
  1425.     }
  1426.     bulkReopenOps[type].setup = reopenOpsPtr->setup;
  1427.     bulkReopenOps[type].finish = reopenOpsPtr->finish;
  1428.     reopensSkipped = 0;
  1429.  
  1430.     return;
  1431. }
  1432.  
  1433.  
  1434. /*
  1435.  *----------------------------------------------------------------------------
  1436.  *
  1437.  * AddReopenHandle --
  1438.  *
  1439.  *    Add a handle to the future reopen rpc info.
  1440.  *
  1441.  * Results:
  1442.  *    None.
  1443.  *
  1444.  * Side effects:
  1445.  *    None.
  1446.  *
  1447.  *----------------------------------------------------------------------------
  1448.  */
  1449. static ReturnStatus
  1450. AddReopenHandle(hdrPtr)
  1451.     Fs_HandleHeader    *hdrPtr;
  1452. {
  1453.     ReturnStatus    status;
  1454.  
  1455.     status = (*bulkReopenOps[hdrPtr->fileID.type].setup) (hdrPtr,
  1456.         bulkHandleSpace[nextHandleIndex].reopenParams);
  1457.     if (status == SUCCESS) {
  1458.     bulkHandleSpace[nextHandleIndex].type = hdrPtr->fileID.type;
  1459.     bulkHandleSpace[nextHandleIndex].serverID = hdrPtr->fileID.serverID;
  1460.     bulkHandleSpace[nextHandleIndex].hdrPtr = hdrPtr;
  1461.     nextHandleIndex++;
  1462.     return SUCCESS;
  1463.     }
  1464.  
  1465.     if (hdrPtr->fileID.type != FSIO_STREAM) {
  1466.     /*
  1467.      * NO_REFERENCE means that there is no current use of the handle,
  1468.      * so it shouldn't be reopened, but there was no failure either, so
  1469.      * don't mark it as a failed reopen.  FS_RECOV_SKIP means it
  1470.      * was a handle with no references but with some clean blocks in
  1471.      * the cache and we're currently skipping reopens on those handles.
  1472.      */
  1473.     if (status == FS_RECOV_SKIP) {
  1474.         RecoveryComplete(&(((Fsrmt_IOHandle *)hdrPtr)->recovery), SUCCESS);
  1475.         reopensSkipped++;
  1476.         return status;
  1477.     }
  1478.     if (status == FS_NO_REFERENCE) {
  1479.         status = SUCCESS;
  1480.     }
  1481.     RecoveryComplete(&(((Fsrmt_IOHandle *)hdrPtr)->recovery), status);
  1482.     }
  1483.     return status;
  1484. }
  1485.  
  1486. /*
  1487.  *----------------------------------------------------------------------------
  1488.  *
  1489.  * FinishReopenHandles --
  1490.  *
  1491.  *    Clean up, mark done with recovery.
  1492.  *
  1493.  * Results:
  1494.  *    None.
  1495.  *
  1496.  * Side effects:
  1497.  *    None.
  1498.  *
  1499.  *----------------------------------------------------------------------------
  1500.  */
  1501. static void
  1502. FinishReopenHandles()
  1503. {
  1504.     int        i;
  1505.     Fsutil_BulkHandle    *bulkHandlePtr;
  1506.     Fsutil_BulkReturn    *returnInfoPtr;
  1507.     Fs_HandleHeader    *hdrPtr;
  1508.     ReturnStatus    status;
  1509.  
  1510.     for (i = 0; i < nextHandleIndex; i++) {
  1511.     bulkHandlePtr = &(bulkHandleSpace[i]);
  1512.     returnInfoPtr = &(bulkReturnSpace[i]);
  1513.     status = returnInfoPtr->status;
  1514.     /*
  1515.      * If there was a bad return status, it's only safe to get header
  1516.      * info, etc., from the handle space and not the return info, because
  1517.      * the return info may not have been filled in on the server if
  1518.      * there was an error.
  1519.      */
  1520.     hdrPtr = bulkHandlePtr->hdrPtr;
  1521.  
  1522.     /* Does server recognize bulk rpc? */
  1523.     if (status == RPC_INVALID_RPC) {
  1524.         Fsutil_HandleUnlock(hdrPtr);
  1525.         continue;
  1526.     }
  1527.  
  1528.     (*bulkReopenOps[bulkHandlePtr->type].finish)
  1529.         (bulkHandlePtr->hdrPtr, returnInfoPtr->state,
  1530.         returnInfoPtr->status);
  1531.     if (bulkHandlePtr->type != FSIO_STREAM) {
  1532.         RecoveryComplete(&(((Fsrmt_IOHandle *)hdrPtr)->recovery), status);
  1533.     }
  1534.  
  1535.     if (bulkHandlePtr->type == FSIO_STREAM && status != SUCCESS) {
  1536.         if (status != RPC_TIMEOUT && status != RPC_SERVICE_DISABLED) {
  1537.         Fsutil_HandleInvalidate(hdrPtr);
  1538.         }
  1539.     }
  1540.         
  1541.     /*
  1542.      * If we removed the handle because it was no longer needed,
  1543.      * we can't try unlocking it.  Otherwise, unlock all I/O handles.
  1544.      */
  1545.     if (status != FS_NO_HANDLE) {
  1546.         Fsutil_HandleUnlock(hdrPtr);
  1547.     }
  1548.     }
  1549.     printf("Reopens skipped: %d\n", reopensSkipped);
  1550.     return;
  1551. }
  1552.  
  1553. /*
  1554.  *----------------------------------------------------------------------------
  1555.  *
  1556.  * DoBulkReopen --
  1557.  *
  1558.  *    Do an RPC to send the collected reopen handles.
  1559.  *
  1560.  * Results:
  1561.  *    Status is SUCCESS unless there's an rpc/network-type failure.
  1562.  *
  1563.  * Side effects:
  1564.  *    RPC.  Status for each handle gets filled in.
  1565.  *
  1566.  *----------------------------------------------------------------------------
  1567.  */
  1568. static ReturnStatus
  1569. DoBulkReopen(serverID)
  1570.     int            serverID;
  1571. {
  1572.     int            inSize;
  1573.     int            outSize;
  1574.     int            i;
  1575.     Fs_HandleHeader    *hdrPtr;
  1576.     ReturnStatus    status;
  1577.     int            numSent;
  1578.     int            numSending;
  1579.     int            maxSendHandles;
  1580.  
  1581.     /*
  1582.      * Unlock all the handles first.  Relock them afterwards.  (In case
  1583.      * the server asks us to do an invalidate or write-back.
  1584.      */
  1585.     if (nextHandleIndex <= 0) {
  1586.     return SUCCESS;
  1587.     }
  1588.     for (i = 0; i < nextHandleIndex; i++) {
  1589.     hdrPtr = bulkHandleSpace[i].hdrPtr;
  1590.     Fsutil_HandleUnlock(hdrPtr);
  1591.     }
  1592.  
  1593.     /*
  1594.      * How many handles can we send in one RPC?  We only want to do our
  1595.      * own fragmentation when sending, so if the return information is
  1596.      * larger, adjust for that on this end.
  1597.      */
  1598.     if (sizeof (Fsutil_BulkHandle) < sizeof (Fsutil_BulkReturn)) {
  1599.     maxSendHandles = RPC_MAX_DATASIZE / sizeof (Fsutil_BulkReturn);
  1600.     } else {
  1601.     maxSendHandles = RPC_MAX_DATASIZE / sizeof (Fsutil_BulkHandle);
  1602.     }
  1603.     numSent = 0;
  1604.     do {
  1605.     numSending = nextHandleIndex - numSent;
  1606.     if (numSending > maxSendHandles) {
  1607.         numSending = maxSendHandles;
  1608.     } 
  1609.     inSize = numSending *  sizeof (Fsutil_BulkHandle);
  1610.     outSize = numSending * sizeof (Fsutil_BulkReturn);
  1611.     status = FsrmtBulkReopen(serverID, inSize,
  1612.         (Address) &(bulkHandleSpace[numSent]), &outSize,
  1613.         (Address) &(bulkReturnSpace[numSent]));
  1614.     if (status != SUCCESS) {
  1615.         break;
  1616.     }
  1617.     numSent += numSending;
  1618.     } while (numSent < nextHandleIndex);
  1619.  
  1620.     for (i = 0; i < nextHandleIndex; i++) {
  1621.     hdrPtr = bulkHandleSpace[i].hdrPtr;
  1622.     Fsutil_HandleLock(hdrPtr);
  1623.     if (status != SUCCESS) {
  1624.         bulkReturnSpace[i].status = status;
  1625.     }
  1626.     }
  1627.     /*
  1628.      * A bad status will only be something like timeout or other rpc-type
  1629.      * failure.
  1630.      */
  1631.     return status;
  1632. }
  1633.  
  1634. /*
  1635.  *----------------------------------------------------------------------------
  1636.  *
  1637.  * Fsutil_DoServerRecovery --
  1638.  *
  1639.  *    Do an RPC to client to start it recovering.  This is called from
  1640.  *    a Proc_CallFunc from recovery device.
  1641.  *
  1642.  * Results:
  1643.  *    None.
  1644.  *
  1645.  * Side effects:
  1646.  *    Starts recovery.
  1647.  *
  1648.  *----------------------------------------------------------------------------
  1649.  */
  1650. ReturnStatus
  1651. Fsutil_DoServerRecovery(clientID)
  1652.     int            clientID;
  1653. {
  1654.     ReturnStatus    status;
  1655.  
  1656.     status = Fsrmt_ServerReopen(clientID);
  1657.     if (status == RPC_INVALID_RPC) {
  1658.     Recov_MarkOldClient(clientID);
  1659.     }
  1660.     /* Timeout on rpc should be handled automatically in Recov_HostDown. */
  1661.  
  1662.     return status;
  1663. }
  1664.